package cn.buk.tms.eotms.controller;

import cn.buk.common.JsonResult;
import cn.buk.common.util.VerifyCodeUtil;
import cn.buk.tms.eotms.dto.DtoLoginStatus;
import cn.buk.tms.eotms.entity.RolePrivilege;
import cn.buk.tms.eotms.entity.User;
import cn.buk.tms.eotms.service.EnterpriseService;
import cn.buk.tms.eotms.service.UserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static cn.buk.tms.eotms.config.SecurityConfiguration.passwordEncoder;
import static cn.buk.tms.eotms.security.LoginUtil.execLoginProcess;
import static cn.buk.tms.eotms.security.LoginUtil.saveLoginInfo2Redis;
import static cn.buk.tms.eotms.util.HttpUtil.getIpAddr;

/**
 * @author yfdai
 */
@RestController
public class LoginController extends BaseController {

  private final Logger logger = LogManager.getLogger(LoginController.class);

  private final int ownerId;

  @Autowired
  public LoginController(UserService userService,
                         EnterpriseService enterpriseService,
                         AuthenticationManager authenticationManager,
                         @Value("${owner_enterprise_id}") int ownerId) {
    this.userService = userService;
    this.enterpriseService = enterpriseService;
    this.authenticationManager = authenticationManager;
    this.ownerId = ownerId;
  }

  private final UserService userService;

  private final EnterpriseService enterpriseService;

  private final AuthenticationManager authenticationManager;


  /**
   *  登录
   * @param openid 微信公众号用户的openid
   * @param bindOpenid 是否将当前openid与用户名密码绑定
   */
  @RequestMapping(value = {"/login"})
  public DtoLoginStatus login(HttpServletRequest request,
      @RequestParam(value = "username", defaultValue = "") final String username,
      @RequestParam(value = "password", required = false) final String password,
      @RequestParam(value = "md5password", required = false) final String md5password,
      @RequestParam(value = "captchaValue", required = false) final String captchaValue,
      @RequestParam(value = "access_token", required = false) final String accessToken,
      @RequestParam(value = "openid", required = false) final String openid,
      @RequestParam(value = "bindOpenid", defaultValue = "false") final boolean bindOpenid
  ) {
    DtoLoginStatus jsonResult = new DtoLoginStatus();

    //校验access_token是否有效
    if (accessToken != null) {
      if (!enterpriseService.validateAccessToken(accessToken)) {
        jsonResult.setErrcode(40001);
        jsonResult.setErrmsg("无效的访问凭证");
        return jsonResult;
      }
    }

    if (username == null || username.trim().length() < 1) {
      jsonResult.setErrcode(40002);
      jsonResult.setErrmsg("请检查用户名和密码");
      return jsonResult;
    }

    if ((password == null || password.length() < 1) && (md5password == null)) {
      jsonResult.setErrcode(40002);
      jsonResult.setErrmsg("请检查用户名和密码");
      return jsonResult;
    }

    final String remoteAddress = getIpAddr(request);
    logger.info("username,password,remoteIp,captcha, openid:" + username + ", " + password + ", " + remoteAddress + ", " + captchaValue + ", " + openid);

    jsonResult.setErrcode(40003);

    User u = userService.getUserByUsername(username.trim());
    if (u == null || u.getParentEnterprise() == 0) {
      jsonResult.setErrmsg("不存在此用户");
      return jsonResult;
    }

    if (this.ownerId > 0 && u.getParentEnterprise() != this.ownerId) {
      jsonResult.setErrmsg("不存在此用户");
      return jsonResult;
    }

    //将传过来的明文密码md5，或传过来的就是md5后的密码
    final String currentPwd = md5password == null ? VerifyCodeUtil.MD5(password) : md5password;

    final String savePwd = u.getMd5Password() == null ? VerifyCodeUtil.MD5(u.getPassword()) : u.getMd5Password();

    if (!currentPwd.equalsIgnoreCase(savePwd)) {
      logger.info("currentPwd:{}, savePwd:{}, equalsIgnoreCase: {}", currentPwd, savePwd, currentPwd.equalsIgnoreCase(savePwd));
      jsonResult.setErrcode(40002);
      jsonResult.setErrmsg("请检查用户名和口令");
      return jsonResult;
    }

    if (u.getStatus() != User.USER_STATUS_NORMAL) {
      jsonResult.setErrcode(40004);
        logger.error("{}: is banned.", username.trim());
      jsonResult.setErrmsg("账号未启用或已停用");

      return jsonResult;
    }

    HttpSession session = request.getSession();
    try {
      logger.info("{}, {}, {}.", u.getUsername(), password, currentPwd);
      execLoginProcess(authenticationManager, session, u.getId(), u.getEnterpriseId(), u.getUsername(), currentPwd, u.getEmpname());
    } catch (AuthenticationException ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage());
      jsonResult.setErrcode(40002);
      jsonResult.setErrmsg("请检查用户名和密码");
      return jsonResult;
    }

    try {
      jsonResult.setGpMode(userService.getGpMode(u.getId()));
    } catch (Exception ex) {
      logger.error(ex.getMessage());
    }

    saveLoginInfo2Redis(jsonResult, u, savePwd, remoteAddress, userService);

    //用户名密码校验成功，查看是否需要进行openid绑定
    if (openid != null && openid.trim().length() > 0 && bindOpenid) {
      try {
        userService.createUserBindWeixin(ownerId, u.getUsername(), openid, u.getEnterpriseId(), u.getId());
      } catch (Exception ex) {
        logger.error(ex.getMessage());
      }
    }

    return jsonResult;
  }

  @RequestMapping({"/my/logout"})
  public JsonResult logout(HttpServletRequest request) {

    logger.info("logout");

    HttpSession session = request.getSession();
    session.invalidate();

    JsonResult jsonResult = new JsonResult();
    jsonResult.setStatus("OK");

    return jsonResult;
  }

  @RequestMapping("/checkLoginStatus")
  public DtoLoginStatus checkLoginStatus(HttpServletRequest request) {

    DtoLoginStatus jsonResult = new DtoLoginStatus();
    jsonResult.setErrcode(10000);

    final String username = getUsername(request);

    if (username != null && username.length() > 0) {

      jsonResult.setUsername(username);
      jsonResult.setUserId(getUserId(request));

      final int enterpriseId = getEnterpriseId(request);
      jsonResult.setEnterpriseId(enterpriseId);
      try {
        jsonResult.setGpMode(userService.getGpMode(getUserId(request)));
      } catch (Exception ex) {
        return jsonResult;
      }

      jsonResult.setErrcode(0);
    }

    return jsonResult;
  }

  @GetMapping("/loginStatus")
  public DtoLoginStatus checkLoginStatus2(HttpServletRequest request) {

    DtoLoginStatus jsonResult = new DtoLoginStatus();
    jsonResult.setErrcode(10000);

    final int userId = getUserId(request);

    if (userId > 0) {
      Optional<DtoLoginStatus> opt = userService.getLoginStatusByUserId(userId);
      if (opt.isPresent()) {
        jsonResult = opt.get();
        try {
          jsonResult.setGpMode(userService.getGpMode(getUserId(request)));
        } catch (Exception ex) {
          logger.warn(ex.getMessage());
        }

        jsonResult.setErrcode(0);
        return jsonResult;
      }
    }

    return jsonResult;
  }

  /**
   * 查找当前用户拥有的权限
   */
  @RequestMapping("/privileges")
  public List<RolePrivilege> searchMyPrivileges(HttpServletRequest request) {
    final int userId = getUserId(request);
    final int enterpriseId = getEnterpriseId(request);

    return userService.searchPrivileges(enterpriseId, userId);
  }

  /**
   * 查找当前用户拥有的角色
   */
  @RequestMapping("/roles")
  public Set<String> searchRoles(HttpServletRequest request) {
    final int userId = getUserId(request);
    final int enterpriseId = getEnterpriseId(request);

    return userService.loadRolesByUserId(enterpriseId, userId);
  }

}
